﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;

namespace AlphaBeatSoundEngine
{

    public class MusicStyle
    {

        private static List<MusicStyle> _MusicStyles;
        public static void Load()
        {
            if (_MusicStyles == null)
            {
                LoadData();
            }
        }
        public static List<MusicStyle> MusicStyles { get {
            if (_MusicStyles == null)
            {
                try
                {
                    LoadData();
                }
                catch (Exception e)
                {
                    throw new Exception("Error while loading styles (XML file may be corrupted) - "+e.Message);
                }
                
            }
            return _MusicStyles;
        } }

        private static void LoadData()
        {
            _MusicStyles = new List<MusicStyle>();
            XDocument xmlDoc = XDocument.Load("MusicStyleData.xml");
            var stylesXml = from style in xmlDoc.Descendants("Style")
                         select style;

            List<TimedTone> tones = new List<TimedTone>();
            List<MusicPattern> patterns = new List<MusicPattern>();
            foreach (var styleXml in stylesXml)
            {
                int tempo = Int32.Parse(styleXml.Attribute("tempo").Value);
                string name = styleXml.Attribute("name").Value;
                MusicStyle style = new MusicStyle(name, tempo);

                //getting partterns
                foreach (var patternXml in styleXml.Descendants("Pattern"))
                {
                    //getting tones and tones length to create pattern
                    foreach (var toneXml in patternXml.Descendants("Tone"))
                    {
                        String duration = toneXml.Attribute("duration").Value;
                        String tone = toneXml.Value;
                        XAttribute markedAttr = toneXml.Attribute("timemarker");
                        bool marked = (markedAttr != null && markedAttr.Value == "true");
                        //using 'tones' list to store our tones, we will clear it after copying it
                        tones.Add(new TimedTone(tone, duration, style, marked));
                    }
                    
                    //creating list at index if not existing yet
                    if (!style._patterns.ContainsKey(tones.Count))
                    {
                        style._patterns.Add(tones.Count, new List<MusicPattern>());
                    }
                    //adding pattern to dictionnary (using 'tones' list to create the array)
                    style._patterns[tones.Count].Add(new MusicPattern(tones.ToArray<TimedTone>()));

                    //clearing 'tones' list to be reused in next loop
                    tones.Clear();
                }

                //getting tones sound files
                foreach(var soundFilesXml in styleXml.Descendants("SoundFile"))
                {

                    TimedTone tone = new TimedTone(soundFilesXml.Attribute("tone").Value,
                                                soundFilesXml.Attribute("duration").Value, style);
                    style._soundsForTimedTones.Add(tone, soundFilesXml.Attribute("location").Value);
                }

                string timeMarkerLocation = "";
                string timeMarkerVolumeStr = "NC";
                //getting time marker sound file and volume (there should be only one)
                foreach (var timeMarkerXml in styleXml.Descendants("TimeMarker"))
                {
                    timeMarkerLocation = timeMarkerXml.Attribute("location").Value;
                    timeMarkerVolumeStr = timeMarkerXml.Attribute("volume").Value;
                }
                int timeMarkerVolume = 100;
                //trying to parse volume
                try { timeMarkerVolume = Int32.Parse(timeMarkerVolumeStr); } catch (Exception e) {}

                style._timeMarkerSoundFile = timeMarkerLocation;
                style._timeMarkerVolume = timeMarkerVolume;

                _MusicStyles.Add(style);
            }

            
        }

        private String _name;
        private int _tempo;
        private string _timeMarkerSoundFile;
        private int _timeMarkerVolume;
        private Dictionary<int, List<MusicPattern>> _patterns; //patternS for word length
        private Dictionary<TimedTone, String> _soundsForTimedTones; //sound path for tone

        public String Name { get { return _name; } }
        public int Tempo { get { return _tempo; } }
        public string TimeMarkerSoundLocation { get { return _timeMarkerSoundFile; } }
        public int TimeMarkerVolume { get { return _timeMarkerVolume; } }

        private MusicStyle(String name, int tempo)
        {
            _name = name;
            _tempo = tempo;
            _patterns = new Dictionary<int, List<MusicPattern>>();
            _soundsForTimedTones = new Dictionary<TimedTone, string>();
        }

        public ICollection<String> GetEveryAvailableSounds()
        {
            return _soundsForTimedTones.Values;
        }

        public String SoundForTone(TimedTone t)
        {
            if(_soundsForTimedTones.ContainsKey(t))
            {
                return _soundsForTimedTones[t];
            } 
            else
            {
                return null;
            }
        }

        public int GetAvailablePatternCountForWordLength(int wordLength)
        {
            if (_patterns.ContainsKey(wordLength))
            {
                return _patterns[wordLength].Count;
            }
            else return -1;
        }

        public List<MusicPattern> GetAvailablePatternsForWordLength(int wordLength)
        {
            if (_patterns.ContainsKey(wordLength))
            {
                return _patterns[wordLength];
            }
            // else
            return null;
        }

        public MusicPattern GetPatternByIndexForWordLength(int wordLength, int index)
        {
            if(_patterns.ContainsKey(wordLength))
            {
                List<MusicPattern> patterns = _patterns[wordLength];
                if (index >= 0 && index < patterns.Count)
                {
                    return patterns.ElementAt<MusicPattern>(index);
                }
            } 
            // else
            return null;
        }

        public override string ToString()
        {
            return "[MusicStyle : Name : '" + _name + "' - Tempo : '"+_tempo.ToString()+"']";
        }
    }
}
